package com.ald.crossex.action.wechat;

import com.ald.crossex.dto.baidu.BDMapRouteMatrixRequest;
import com.ald.crossex.dto.baidu.BDMapRouteMatrixResponse;
import com.ald.crossex.dto.wechat.*;
import com.ald.crossex.entity.TCeCoreWechat;
import com.ald.crossex.service.wechat.WechatService;
import com.ald.crossex.system.SystemCache;
import com.ald.crossex.system.SystemConfig;
import com.alibaba.fastjson.JSON;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.log4j.Logger;
import org.marker.weixin.MySecurity;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;

/**
 * Created by lishijiong on 15/3/19.
 * 网页授权流程
 * 1、引导用户进入授权页面同意授权，获取code
 * 2、通过code换取网页授权access_token（与基础支持中的access_token不同）
 * 3、如果需要，开发者可以刷新网页授权access_token，避免过期
 * 4、通过网页授权access_token和openid获取用户基本信息（支持UnionID机制）
 */

public class BaseController {

    protected static Logger logger = Logger.getLogger(BaseController.class);


    /**
     * 网页授权获取用户基本信息
     *
     * @param wechatService
     * @param code
     * @param state
     */
    protected TCeCoreWechat webAuthorize(WechatService wechatService, String code, String state) {
        logger.info("method webAuthorize : code=" + code);
        WechatWebAccessTokenResponse token = getAccessTokenByCode(code);
        List<TCeCoreWechat> wechats = wechatService.getWechatByOpenId(token.getOpenid());
        TCeCoreWechat wechat;

        if(wechats!=null && wechats.size()>0){
            wechat = wechats.get(0);
            return wechat;
        }else {
            if (token.getAccess_token() != null && token.getOpenid() != null) {
                if (!checkAccessToken(token.getAccess_token(), token.getOpenid())) {
                    token = refreshAccessToken(token.getRefresh_token());
                }
                String lang = "zh_CN";
                WechatWebUserInfoResponse userInfo = getWechatUserInfo(token.getAccess_token(), token.getOpenid(), lang);
                wechat = wechatService.addWechat(SystemConfig.getVal("wechat_mp_AppID"), "zh_CN", userInfo);
                return wechat;
            }
        }
        return null;

    }

    /**
     * 生成JsSDK配置信息
     *
     * @param request
     * @param mav
     * @param code
     * @param state
     */
    protected void generateJsSDKConfig(HttpServletRequest request, ModelAndView mav, String code, String state) {
        long timestamp = System.currentTimeMillis();
        String url = request.getRequestURL().toString() + "?code=" + code + "&state=" + state;
        String noncestr = SystemConfig.getVal("wechat_mp_nonceStr");
        String jsapi_ticket = (String) SystemCache.get("jsapi_ticket").getObject();
        String signature = "jsapi_ticket=" + jsapi_ticket + "&noncestr=" + noncestr + "&timestamp=" + timestamp + "&url=" + url;
        MySecurity security = new MySecurity();
        logger.info("before Security encode " + signature);
        signature = security.encode(signature, MySecurity.SHA_1);
        logger.info("after Security encode " + signature);
        mav.addObject("appId", SystemConfig.getVal("wechat_mp_AppID"));
        mav.addObject("timestamp", timestamp);
        mav.addObject("nonceStr", noncestr);
        mav.addObject("signature", signature);
        mav.addObject("ak",SystemConfig.getVal("baidu_map_ak"));
    }

    /**
     * 通过code换取网页授权access_token
     *
     * @param code
     * @return
     */
    protected WechatWebAccessTokenResponse getAccessTokenByCode(String code) {
        HttpGet get = null;
        String requestUrl = SystemConfig.getVal("web_access_token_url") + "?appid=" + SystemConfig.getVal("wechat_mp_AppID")
                + "&secret=" + SystemConfig.getVal("wechat_mp_AppSecret") + "&code=" + code + "&grant_type=authorization_code";
        logger.info("method getAccessTokenByCode properties requestUrl is " + requestUrl);
        try {
            HttpClient client = new DefaultHttpClient();
            get = new HttpGet(requestUrl);
            HttpResponse response = client.execute(get);
            if (response.getStatusLine().getStatusCode() == 200) {
                InputStream inputStream = response.getEntity().getContent();
                BufferedReader reader = new BufferedReader(new InputStreamReader(
                        inputStream, "UTF-8"));
                StringBuffer buffer = new StringBuffer();
                String line = "";
                while ((line = reader.readLine()) != null) {
                    buffer.append(line);
                }

                String jsonResult = buffer.toString();
                logger.info("http response is " + jsonResult);
                return JSON.parseObject(jsonResult, WechatWebAccessTokenResponse.class);
            } else {
                throw new Exception("请求微信服务器异常返回！http 状态码：" + response.getStatusLine().getStatusCode());
            }
        } catch (Exception e) {
            logger.error("请求微信服务器失败！", e);
            return null;
        } finally {
            get.releaseConnection();
        }
    }

    /**
     * 刷新access_token（如果需要）
     *
     * @param refreshToken
     * @return
     */
    protected WechatWebAccessTokenResponse refreshAccessToken(String refreshToken) {
        HttpGet get = null;
        String requestUrl = SystemConfig.getVal("web_access_token_refresh_url") + "?appid=" + SystemConfig.getVal("wechat_mp_AppID")
                + "&refresh_token=" + refreshToken + "&grant_type=refresh_token";
        logger.info("method getAccessTokenByCode properties requestUrl is " + requestUrl);
        try {
            HttpClient client = new DefaultHttpClient();
            get = new HttpGet(requestUrl);
            HttpResponse response = client.execute(get);
            if (response.getStatusLine().getStatusCode() == 200) {
                InputStream inputStream = response.getEntity().getContent();
                BufferedReader reader = new BufferedReader(new InputStreamReader(
                        inputStream, "UTF-8"));
                StringBuffer buffer = new StringBuffer();
                String line = "";
                while ((line = reader.readLine()) != null) {
                    buffer.append(line);
                }

                String jsonResult = buffer.toString();
                logger.info("http response is " + jsonResult);
                return JSON.parseObject(jsonResult, WechatWebAccessTokenResponse.class);
            } else {
                throw new Exception("请求微信服务器异常返回！http 状态码：" + response.getStatusLine().getStatusCode());
            }
        } catch (Exception e) {
            logger.error("请求微信服务器失败！", e);
            return null;
        } finally {
            get.releaseConnection();
        }
    }

    /**
     * 拉取用户信息(需scope为 snsapi_userinfo)
     *
     * @param access_token
     * @param openid
     * @param lang
     * @return
     */
    protected WechatWebUserInfoResponse getWechatUserInfo(String access_token, String openid, String lang) {

        HttpGet get = null;
        String requestUrl = SystemConfig.getVal("web_user_info_url") + "?access_token=" + access_token
                + "&openid=" + openid + "&lang=" + lang;
        logger.info("method getAccessTokenByCode properties requestUrl is " + requestUrl);
        try {
            HttpClient client = new DefaultHttpClient();
            get = new HttpGet(requestUrl);
            HttpResponse response = client.execute(get);
            if (response.getStatusLine().getStatusCode() == 200) {
                InputStream inputStream = response.getEntity().getContent();
                BufferedReader reader = new BufferedReader(new InputStreamReader(
                        inputStream, "UTF-8"));
                StringBuffer buffer = new StringBuffer();
                String line = "";
                while ((line = reader.readLine()) != null) {
                    buffer.append(line);
                }

                String jsonResult = buffer.toString();
                logger.info("http response is " + jsonResult);
                return JSON.parseObject(jsonResult, WechatWebUserInfoResponse.class);
            } else {
                throw new Exception("请求微信服务器异常返回！http 状态码：" + response.getStatusLine().getStatusCode());
            }
        } catch (Exception e) {
            logger.error("请求微信服务器失败！", e);
            return null;
        } finally {
            get.releaseConnection();
        }

    }

    /**
     * 检验授权凭证（access_token）是否有效
     *
     * @param access_token
     * @param openid
     * @return
     */
    protected boolean checkAccessToken(String access_token, String openid) {

        HttpGet get = null;
        String requestUrl = SystemConfig.getVal("web_access_token_check_url") + "?access_token=" + access_token
                + "&openid=" + openid;
        logger.info("method getAccessTokenByCode properties requestUrl is " + requestUrl);
        try {
            HttpClient client = new DefaultHttpClient();
            get = new HttpGet(requestUrl);
            HttpResponse response = client.execute(get);
            if (response.getStatusLine().getStatusCode() == 200) {
                InputStream inputStream = response.getEntity().getContent();
                BufferedReader reader = new BufferedReader(new InputStreamReader(
                        inputStream, "UTF-8"));
                StringBuffer buffer = new StringBuffer();
                String line = "";
                while ((line = reader.readLine()) != null) {
                    buffer.append(line);
                }

                String jsonResult = buffer.toString();
                logger.info("http response is " + jsonResult);
                WechatBaseResponse rsp = JSON.parseObject(jsonResult, WechatBaseResponse.class);
                if (rsp.getErrcode() == 0) {
                    return true;
                } else {
                    throw new Exception("检验授权凭证（access_token）是否有效失败！" + rsp.getErrcode() + ":" + rsp.getErrmsg());
                }
            } else {
                throw new Exception("请求微信服务器异常返回！http 状态码：" + response.getStatusLine().getStatusCode());
            }
        } catch (Exception e) {
            logger.error("请求微信服务器失败！", e);
            return false;
        } finally {
            get.releaseConnection();
        }

    }

    /**
     * 计算两个地址距离时间
     * @param request
     * @return
     */
    protected BDMapRouteMatrixResponse calculateDistance(BDMapRouteMatrixRequest request) {

        HttpGet get = null;
        String requestUrl = SystemConfig.getVal("baidu_map_routematrix_url") + "?output=json&origins="+request.getOrigins()
                +"&destinations="+request.getDestinations()+"&mode="+request.getMode()+"&tactics="+request.getTactics()
                +"&ak="+request.getAk();
        logger.info("method calculateDistance properties requestUrl is " + requestUrl);
        try {
            HttpClient client = new DefaultHttpClient();
            get = new HttpGet(requestUrl);
            HttpResponse response = client.execute(get);
            if (response.getStatusLine().getStatusCode() == 200) {
                InputStream inputStream = response.getEntity().getContent();
                BufferedReader reader = new BufferedReader(new InputStreamReader(
                        inputStream, "UTF-8"));
                StringBuffer buffer = new StringBuffer();
                String line = "";
                while ((line = reader.readLine()) != null) {
                    buffer.append(line);
                }

                String jsonResult = buffer.toString();
                logger.info("http response " + jsonResult);
                jsonResult = BDMapRouteMatrixResponse.routeMatrixReturnConvert(jsonResult);
                logger.debug("jsonResult convert "+jsonResult);
                BDMapRouteMatrixResponse rsp = JSON.parseObject(jsonResult, BDMapRouteMatrixResponse.class);
                return rsp;
            } else {
                throw new Exception("调用百度地图服务器返回异常！http 状态码：" + response.getStatusLine().getStatusCode());
            }
        } catch (Exception e) {
            logger.error("调用百度地图服务器返回失败！", e);
            return null;
        } finally {
            get.releaseConnection();
        }

    }
}
